#include<functional>
#include<iostream>
#include<memory>
#include<vector>
#include<unordered_map>
#include<unistd.h>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

//封装定时任务对象  通过析构函数和shared_ptr实现延迟销毁

class TimerTask
{

private:
    uint64_t _id;  //标识该任务对象id
    uint32_t _timeout; //超时时间
    TaskFunc _task_cb; // 要执行的定时任务
    ReleaseFunc _release; //用于删除timewheel中保存的定时任务对象信息 
    bool _canceled; //false 表示未被取消  true，表示取消

public:
    TimerTask(uint64_t id,uint32_t delay,const TaskFunc & cb)
    :_id(id)
    ,_timeout(delay)
    ,_task_cb(cb)
    ,_canceled(false)
    {}

    ~TimerTask()
    {
        //析构的时候再执行定时任务
        if(_canceled == false)
        {
            _task_cb();
            _release();
        }

    }
    void TimerCancle( )
    {
        _canceled = true;
    }


    void SetRelease(const ReleaseFunc& re)  //设置
    {
       _release = re;
       return;
    }

    uint32_t DelayTime()
    {
        return _timeout;   //获取延迟时间
    }


};


//时间轮
class TimeWheel
{

private:
    using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;

    int _tick; //秒针，指到哪执行到哪里
    int _capacity; //表盘的最大数量，即最大的延迟时间
        //用二维数组存储时间段及该时间的定时任务
    std::vector<std::vector<PtrTask>> _wheel;
    //建立定时任务id和weakptr的映射关系   涉及share_ptr的缺陷
    std::unordered_map<uint64_t,WeakTask> _timers;
private:
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it != _timers.end()) //找到该定时任务
        {
            _timers.erase(it);
        }
        return;
    }


public:
    TimeWheel()
    :_capacity(60)
    ,_tick(0)
    ,_wheel(_capacity)
    {}


    void TimerAdd(uint64_t id,uint32_t delay,const TaskFunc & cb)  //添加定时任务
    {   
        PtrTask pt(new TimerTask(id,delay,cb));
        pt->SetRelease(std::bind(&TimeWheel::RemoveTimer,this,id));  //为什么要&

        _timers[id] = WeakTask(pt);
        int pos = (_tick+ delay)%_capacity;  //循环队列一样
        _wheel[pos].push_back(pt);  //插入延迟任务

    }

    void TimerRefresh(uint64_t id)   //刷新/延迟定时任务
    {
        //通过保存的定时器对象中的weak_ptr构造一个share_ptr，添加到轮子
        auto it = _timers.find(id);
        if(it == _timers.end())
        {
            return; //没该定时任务，返回
        }
        PtrTask pt = it->second.lock();  //lock获取weak_ptr管理的对象对应的shared_ptr
        uint32_t delay = pt->DelayTime();
        int pos = (_tick+ delay)%_capacity;  //循环队列一样

        _wheel[pos].push_back(pt);  //插入延迟任务
    }

    void TimerCancle(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
        {
            return; //没该定时任务，返回
        }

        //找到后调用
        PtrTask pt = it->second.lock();
        pt->TimerCancle();
        return;
    }



    void RunTimerTask()  //执行定时任务，应该每秒执行一次，相当于秒针走一步
    {
        _tick = (_tick+1)%_capacity;

        _wheel[_tick].clear();  //清空该位置的定时任务，自动调用定时任务对象的析构

    }
    
};

class Test
{
public:
    Test(){std::cout<<"构造"<<std::endl;}
    ~Test(){std::cout<<"析构"<<std::endl;}
};

void DelTest(Test* t)
{
    delete t;
}


int main()
{
    TimeWheel tw; //创建一个时间轮对象
    Test* t = new Test();

    tw.TimerAdd(888,5,std::bind(DelTest,t));

    for(int i=0;i<5;++i)
    {
        sleep(1);
        tw.TimerRefresh(888);  //刷新任务
        tw.RunTimerTask(); //秒针移动
        std::cout<<"刷新了定时任务,重新需5秒中后销毁"<<std::endl;
        tw.TimerCancle(888);
    }

    //测试结果应当再过五秒后打印
    while(1)
    {
        sleep(1);
        std::cout<<"--------------------------\n";
        tw.RunTimerTask();
    }

    return 0;
}

